(*
	sendSPort string -- Send a string to the serial port driver, paying attention to the flags for
		appending a linefeed after a carriage return, and for auto-wrapping the output.

	To compile and link this file using Macintosh Programmer's Workshop,

		pascal -w sendSPort.p
		link -m ENTRYPOINT -o HyperCommands -rt XCMD=7033 -sn Main=sendSPort ¶
			sendSPort.p.o "{MPW}"Libraries:interface.o

	© Copyright 1987,88 by Apple Computer, Inc.

	Initial coding 9/87 by Harry R. Chesley.
*)

{$R-}

{$S sendSPort } 	{ Segment name must be the same as the command name. }

unit DummyUnit;

interface

uses MemTypes, QuickDraw, OSIntf, HyperXCmd;

procedure EntryPoint(paramPtr: XCmdPtr);
	
implementation

const

return = 13;				{ Carriage return. }
linefeed = 10;			{ Line feed. }
space = ord(' ');		{ Space. }

type

Str31 = String[31];

procedure sendSPort(paramPtr: XCmdPtr); forward;

procedure EntryPoint(paramPtr: XCmdPtr);

	begin
		sendSPort(paramPtr);
	end;

procedure sendSPort(paramPtr: XCmdPtr);

	var io: ParmBlkPtr;
		col: integer;

	{$I XCmdGlue.inc}

	procedure Fail(errMsg: Str255); { set theResult and quit }
		begin
			paramPtr^.returnValue := PasToZero(errMsg);
			exit(sendSPort);
		end;

	{$I SPortUtil.inc}

	function copyAndCount(copyFrom, copyTo: Ptr; var col: integer; doTheCopy: boolean): longInt;
		{ Copy and translate bytes from the source string to the destination, counting the size of the destination
			as we go. If doTheCopy is not true, then don't actually do the copy, just accumulate the count. It assumes
			that we're starting in the column indicated by col, and returns the new column in col. }

		var fromPtr, toPtr, nextFromPtr: Ptr;
			nextCol: integer;
			theChar: SignedByte;

		procedure copyOne(d: SignedByte);

			begin
				if doTheCopy then toPtr^ := d;
				toPtr := pointer(ord4(toPtr)+1);
				col := col+1;
			end;

		procedure copyCRLF;

			begin
				copyOne(return);
				if ThisSPort.sendLFs then copyOne(linefeed);
				col := 1;
			end;

		begin
		{ Cycle thru all the bytes to be copied. }
		fromPtr := copyFrom; toPtr := copyTo;
		while fromPtr^ <> 0 do
			begin
				{ Get the next byte. }
				theChar := fromPtr^;
				fromPtr := pointer(ord4(fromPtr)+1);
				{ Check if it was a return. }
				if theChar = return then copyCRLF
				{ Otherwise, check for auto-wrap on space. }
				else if ThisSPort.autoWrap and (theChar = space) and (col <= WRAPCOLUMN) then
					begin
						{ Send the space. }
						copyOne(space);
						{ This was a space, so we may want to auto-wrap here. Find out where the next auto-wrap
							would occur. }
						nextFromPtr := fromPtr;
						nextCol := col;
						while (nextFromPtr^ <> return) and (nextFromPtr^ <> space) and (nextFromPtr^ <> 0) do
							begin
								nextFromPtr := pointer(ord4(nextFromPtr)+1);
								nextCol := nextCol+1;
							end;
						{ If the next auto-wrap is past the wrap column, then auto-wrap here. }
						if (nextCol > WRAPCOLUMN) and (fromPtr^ <> return) and (fromPtr^ <> 0) then copyCRLF;
					end
				{ Otherwise, check for a forced auto-wrap (one word larger than a line). }
				else if ThisSPort.autoWrap and (col >= WRAPCOLUMN) then
					begin
						if col = WRAPCOLUMN then copyOne(space);
						copyCRLF;
						copyOne(theChar);
					end
				else copyOne(theChar);
			end;

			{ Compute the final size of the output. }
			copyAndCount := ord4(toPtr) - ord4(copyTo);
		end;

	begin
		if paramPtr^.paramCount <> 1 then Fail('parameter count is not 1');

		SetUpSPortGlobals;
		EnsureOpenPort;

		{ Check for an empty string being sent. }
		if paramPtr^.params[1] = nil then exit(sendSPort);
		if paramPtr^.params[1]^^ = 0 then exit(sendSPort);

		{ Get an I/O block. }
		io := WaitForFreeIOBlk;

		{ Get rid of the old buffer, if any. }
		if io^.ioBuffer <> nil then DisposPtr(io^.ioBuffer);
		{ Figure out the size of the new buffer and allocate it. }
		col := ThisSPort.currentColumn;
		io^.ioBuffer := NewPtr(copyAndCount(paramPtr^.params[1]^,nil,col,false));
		if io^.ioBuffer = nil then Fail('could not allocate buffer');

		{ Copy the data into the buffer, and set the output request size. }
		col := ThisSPort.currentColumn;
		io^.ioReqCount := copyAndCount(paramPtr^.params[1]^,io^.ioBuffer,col,true);

		{ Send the data to the port asynchronously. }
		if PBWrite(io,true) <> noErr then Fail('PBWrite failed');

		{ Remember the column. }
		Globals^^.ports[Globals^^.selectedPort].currentColumn := col;
	end;

end.
